/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package memsim.instructions;
import memsim.MemoryManager;
import memsim.RegisterHandler;
import memsim.SymbolTable;
import memsim.Alu;
/**
 * FDEInstructionCycles class does fetch, decode and execute instructions
 * depends on what opcode it will get from symbol table
 * @author kimchouSok
 */
public class FDEInstructionCycles {

    static SymbolTable symbolTable = new SymbolTable();
    private static int opCode, dst, src1, src2, src3;
    private boolean empty = false;

    //constructor
    public FDEInstructionCycles(int opcode, int dstReg, int srcReg1, int srcReg2){
         opCode = opcode;
         dst = dstReg;
         src1 = srcReg1;
         src2 = srcReg2;
          if((opcode == 0) && (dstReg == 0) &&(srcReg1 == 0) &&(srcReg2 == 0))
          {
            empty = true;
            System.out.println("i'm empty");
          }

    }

    //getFetch method getvalue from pc address and increment pc
     public static int getFetch(MemoryManager m, RegisterHandler regHandler ){
        int instrAddress = regHandler.getPC();
        String temp = m.getValue(instrAddress).toString();
        int content = Integer.parseInt(temp);
        regHandler.incPC();
        System.out.println("Increasing PC " + content);
        return content;
    }

    //decode uses logical right shift on each opcode, dstReg, src1, src2 by 5 bits
    public static FDEInstructionCycles ShiftOpCodeDstSrc1Src2(int opcode, int dstReg, int src1, int src2){
        int tempOpcode, tempDst, tempSrc1, tempSrc2;
        tempOpcode = opcode >>> 27;

        tempDst = dstReg >>> 22;
        tempDst = tempDst & 31;

        tempSrc1 = src1 >>> 17;
        tempSrc1 = tempSrc1 & 31;

        tempSrc2 = src2 >>> 12;
        tempSrc2 = tempSrc2 & 31;

        FDEInstructionCycles FDE = new FDEInstructionCycles(tempOpcode, tempDst, tempSrc1, tempSrc2);

        return FDE;

    }

    /* execute method executes instruction depends on what kind of opcode
     * I get from symboltable(add,and,nots,ors,subs, loads,br, strs)
     */
      public static int Execute( Alu alu, MemoryManager m, RegisterHandler rH){
        
          int op = getOpcode();
          FDEInstructionCycles fde = ShiftOpCodeDstSrc1Src2(getOpcode(),getDstReg(),getSrcReg1(),getSrcReg2());
          if(!fde.isEmpty())
         {
            if((symbolTable.map.get(op)).equals("ADDS")){
               rH.setValue(getDstReg(), alu.adds.addScalar(rH.getValue(getSrcReg1()), rH.getValue(getSrcReg2())));
               alu.updateCycle(3);
               System.out.println("add");
               System.out.println(getDstReg());
            }
            else if((symbolTable.map.get(op)).equals("ANDS")){
                rH.setValue(getDstReg(), alu.ands.andScalar(getSrcReg1(), getSrcReg2()));
                alu.updateCycle(3);
                System.out.println("and");
            }
            else if((symbolTable.map.get(op)).equals("NOTS")){
                rH.setValue(getDstReg(), alu.nots.notScalar(getSrcReg1()));
                alu.updateCycle(2);
                System.out.println("not");
            }
            else if((symbolTable.map.get(op)).equals("ORS")){
                rH.setValue(getDstReg(), alu.ors.orScalar(getSrcReg1(), getSrcReg2()));
                alu.updateCycle(3);
                System.out.println("or");
            }
            else if((symbolTable.map.get(op)).equals("SUBS")){
                rH.setValue(getDstReg(), alu.subs.subScalar(getSrcReg1(), getSrcReg2()));
                alu.updateCycle(3);
                System.out.println("sub");
            }
            else if ((symbolTable.map.get(op)).equals("BR")){
               alu.br.unConditionalBr(getDstReg(), rH);
               alu.updateCycle(2);
               System.out.println("br");
            }
            else if ((symbolTable.map.get(op)).equals("STRS")){
               alu.strs.storeInMemory(getDstReg(), getSrcReg1(), m, rH);
               alu.updateCycle(100);
               System.out.println("str");
            }
            else if ((symbolTable.map.get(op)).equals("LDR")){
               alu.ldr.loadRegister(getDstReg(), getSrcReg1(), rH, m);
               alu.updateCycle(100);
               System.out.println("ld");
            }

        }
        return 0;
    }

        //return opcode
    public static int getOpcode(){
        return opCode;
    }

    //return dst
    public static int getDstReg(){
        return dst;
    }

    //return src1
    public static int getSrcReg1(){
        return src1;
    }

    //return src2
    public static int getSrcReg2(){
        return src2;
    }
    public boolean isEmpty()
    {
        return empty;
    }
}